/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* E.P. Scene Graph
* Developed by:
*       - Eduardo Ribeiro (eribeiro @ tecgraf . puc-rio . br)
*       - Peter Dam (peter @ tecgraf . puc-rio . br)
* File: Vec3.h
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef _EPSG_VEC3_
#define _EPSG_VEC3_

#include <math.h>

namespace EPSG
{
	template <typename T>
	class Vec3
	{
	public:
		/* [CONSTRUCTOR] */	Vec3();
		/* [CONSTRUCTOR] */	Vec3( T x, T y, T z );

		EPSG::Vec3<T>		operator+( const Vec3& rhs );
		EPSG::Vec3<T>&		operator+=( const Vec3& rhs );
		EPSG::Vec3<T>		operator-( const Vec3& rhs );
		EPSG::Vec3<T>&		operator-=( const Vec3& rhs );
		EPSG::Vec3<T>		operator*( const Vec3& rhs );
		EPSG::Vec3<T>&		operator*=( const Vec3& rhs );
		void				operator=( const Vec3& rhs );
		T&					operator[]( int index );

		void				setValues( T x, T y, T z );
		float				normalize();
		float				length();
		
		static EPSG::Vec3<T>	cross( const Vec3& a, const Vec3& b );

		T					x, y, z;
	};
}

/* TEMPLATE METHODS */
template <typename T>
EPSG::Vec3<T>::Vec3() : x( 0 ), y( 0 ), z( 0 )
{
	
}

template <typename T>
EPSG::Vec3<T>::Vec3( T x, T y, T z )
{
	this->x = x;
	this->y = y;
	this->z = z;
}

/* OPERATORS */
template <typename T>
EPSG::Vec3<T> EPSG::Vec3<T>::operator+( const Vec3& rhs )
{
	EPSG::Vec3<T> ret;
	ret = *this;
	ret += rhs;
	return ret;
}

template <typename T>
EPSG::Vec3<T>& EPSG::Vec3<T>::operator+=( const Vec3& rhs )
{
	x += rhs.x;
	y += rhs.y;
	z += rhs.z;

	return *this;
}

template <typename T>
EPSG::Vec3<T> EPSG::Vec3<T>::operator-( const Vec3& rhs )
{
	EPSG::Vec3<T> ret;
	ret = *this;
	ret -= rhs;
	return ret;
}

template <typename T>
EPSG::Vec3<T>& EPSG::Vec3<T>::operator-=( const Vec3& rhs )
{
	x -= rhs.x;
	y -= rhs.y;
	z -= rhs.z;

	return *this;
}

template <typename T>
EPSG::Vec3<T> EPSG::Vec3<T>::operator*( const Vec3& rhs )
{
	EPSG::Vec3<T> ret;
	ret = *this;
	ret *= rhs;
	return ret;
}

template <typename T>
EPSG::Vec3<T>& EPSG::Vec3<T>::operator*=( const Vec3& rhs )
{
	x *= rhs.x;
	y *= rhs.y;
	z *= rhs.z;

	return *this;
}

template <typename T>
void EPSG::Vec3<T>::operator=( const Vec3& rhs )
{
	x = rhs.x;
	y = rhs.y;
	z = rhs.z;

}

template <typename T>
T& EPSG::Vec3<T>::operator[]( int index )
{
	switch( index )
	{
	case 0:
		return x;
	case 1:
		return y;
	case 2:
		return z;
	default:
		return NULL;
	}
}

template <typename T>
void EPSG::Vec3<T>::setValues( T x, T y, T z )
{
	this->x = x;
	this->y = y;
	this->z = z;
}

template <typename T>
EPSG::Vec3<T> EPSG::Vec3<T>::cross( const Vec3& a, const Vec3& b )
{
	return EPSG::Vec3<float>( a.y * b.z - b.y * a.z, b.x * a.z - a.x * b.z, a.x * b.y - b.x * a.y );
}

template <typename T>
float EPSG::Vec3<T>::length()
{
    return (float)sqrt( x*x + y*y + z*z );
}

template <typename T>
float EPSG::Vec3<T>::normalize()
{
	float l = length();
	if( l != 0.0 )
	{
		float d = 1 / l;
		x *= d; y *= d; z *= d;
	}
	return l;
}

#endif //_EPSG_VEC3_